﻿/**
 * Peter
 * Created by: Peter Development Team
 *    http://peter.codeplex.com/
 * 
 * GNU General Public License version 2 (GPLv2)
 *    http://peter.codeplex.com/license
 **/

using System;
using System.ComponentModel.Composition;
using System.Windows.Media;
using System.Xml.Serialization;
using Peter.Common;
using Peter.Common.Interfaces;
using Peter.Common.MainMenu;
using Peter.Common.Utilities;

namespace Peter.Data
{
   /// <summary>
   /// Represents the options for the avalon text edit control.
   /// </summary>
   [Export (typeof (IOptionPage))]
   public class OptionsEditor : ViewModelBase, IOptionPage
   {
      #region Fields

      private int m_IndentSize;
      private bool m_HighlightCurrentLine;
      private bool m_ShowLineNumbers;
      private bool m_WrapText;
      private bool m_EnableEmails;
      private bool m_EnableHyperlinks;
      private bool m_ShowTabs;
      private bool m_ShowSpaces;
      private bool m_ShowEol;
      private bool m_ConvertTabsToSpaces;
      private bool m_AllowScrollPastDocument;
      private bool m_HoldCtrlForHyperlinks;
      private FontFamily m_SelectedFont;
      private string m_FontName;
      private double m_FontSize;
      private bool m_CodeFolding;
      private Color m_HighlightLineColor;
      private Color m_HighlightLineBorderColor;
      private double m_HighlightLineThickness;

      #endregion

      #region Setup

      /// <summary>
      /// Intializes a new global editor properties object.
      /// </summary>
      public OptionsEditor () 
      { 
         this.SetDefaults ();
      }

      /// <summary>
      /// Sets the default properties.
      /// </summary>
      public void SetDefaults ()
      {
         this.ShowLineNumbers = true;
         this.WrapText = false;
         this.EnableEmails = false;
         this.EnableHyperlinks = false;
         this.ShowTabs = false;
         this.ShowSpaces = false;
         this.ShowEol = false;
         this.IndentSize = 3;
         this.ConvertTabsToSpaces = true;
         this.AllowScrollPastDocument = true;
         this.HoldCtrlForHyperlinks = true;
         this.FontName = "Courier New";
         this.FontSize = 12;
         this.m_CodeFolding = true;
      }

      #endregion

      #region Properties

      /// <summary>
      /// Gets or Sets if the editors should show line numbers or not.
      /// </summary>
      public bool ShowLineNumbers 
      {
         get { return this.m_ShowLineNumbers; }
         set
         {
            this.m_ShowLineNumbers = value;
            this.RaisePropertyChanged ("ShowLineNumbers");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should highlight the current line or not.
      /// </summary>
      public bool HighlightCurrentLine
      {
         get { return this.m_HighlightCurrentLine; }
         set
         {
            this.m_HighlightCurrentLine = value;
            this.RaisePropertyChanged ("HighlightCurrentLine");
         }
      }

      /// <summary>
      /// Gets or Sets the color for highlighting the current line.
      /// </summary>
      public Color HighlightLineColor
      {
         get { return this.m_HighlightLineColor; }
         set
         {
            this.m_HighlightLineColor = value;
            this.RaisePropertyChanged ("HighlightLineColor");
         }
      }

      /// <summary>
      /// Gets or Sets the color for the border of highlighting the current line.
      /// </summary>
      public Color HighlightLineBorderColor
      {
         get { return this.m_HighlightLineBorderColor; }
         set
         {
            this.m_HighlightLineBorderColor = value;
            this.RaisePropertyChanged ("HighlightLineBorderColor");
         }
      }

      /// <summary>
      /// Gets or Set the thickness of the border of the highlighted line.
      /// </summary>
      public double HighlightLineThickness
      {
         get { return this.m_HighlightLineThickness; }
         set
         {
            this.m_HighlightLineThickness = value;
            this.RaisePropertyChanged ("HighlightLineThickness");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should word wrap or not.
      /// </summary>
      public bool WrapText
      {
         get { return this.m_WrapText; }
         set
         {
            this.m_WrapText = value;
            this.RaisePropertyChanged ("WrapText");
         }
      }

      /// <summary>
      /// Gets or Sets if ctrl should be held to follow hyperlinks or not.
      /// </summary>
      public bool HoldCtrlForHyperlinks
      {
         get { return this.m_HoldCtrlForHyperlinks; }
         set
         {
            this.m_HoldCtrlForHyperlinks = value;
            this.RaisePropertyChanged ("HoldCtrlForHyperlinks");
         }
      }

      /// <summary>
      /// Gets or Sets if the editor is allowed to scroll past the end of the doucment or not.
      /// </summary>
      public bool AllowScrollPastDocument
      {
         get { return this.m_AllowScrollPastDocument; }
         set
         {
            this.m_AllowScrollPastDocument = value;
            this.RaisePropertyChanged ("AllowScrollPastDocument");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should convert tabs to spaces or not.
      /// </summary>
      public bool ConvertTabsToSpaces
      {
         get { return this.m_ConvertTabsToSpaces; }
         set
         {
            this.m_ConvertTabsToSpaces = value;
            this.RaisePropertyChanged ("ConvertTabsToSpaces");
         }
      }

      /// <summary>
      /// Gets or Sets the editors indention size.
      /// </summary>
      public int IndentSize
      {
         get { return this.m_IndentSize; }
         set
         {
            this.m_IndentSize = value;
            this.RaisePropertyChanged ("IndentSize");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should show end of line symbols or not.
      /// </summary>
      public bool ShowEol
      {
         get { return this.m_ShowEol; }
         set
         {
            this.m_ShowEol = value;
            this.RaisePropertyChanged ("ShowEOL");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should show space symbols or not.
      /// </summary>
      public bool ShowSpaces
      {
         get { return this.m_ShowSpaces; }
         set
         {
            this.m_ShowSpaces = value;
            this.RaisePropertyChanged ("ShowSpaces");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should show tab symbols or not.
      /// </summary>
      public bool ShowTabs
      {
         get { return this.m_ShowTabs; }
         set
         {
            this.m_ShowTabs = value;
            this.RaisePropertyChanged ("ShowTabs");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should highlight hyperlinks or not.
      /// </summary>
      public bool EnableHyperlinks
      {
         get { return this.m_EnableHyperlinks; }
         set
         {
            this.m_EnableHyperlinks = value;
            this.RaisePropertyChanged ("EnableHyperlinks");
         }
      }

      /// <summary>
      /// Gets or Sets if the editors should highlight emails or not.
      /// </summary>
      public bool EnableEmails
      {
         get { return this.m_EnableEmails; }
         set
         {
            this.m_EnableEmails = value;
            this.RaisePropertyChanged ("EnableEmails");
         }
      }

      /// <summary>
      /// Gets or Sets the name of the editor's font.
      /// </summary>
      public string FontName
      {
         get { return this.m_FontName; }
         set
         {
            if (this.m_FontName != value)
            {
               this.m_FontName = value;
               this.RaisePropertyChanged ("FontName");
               this.SetSelectedFont ();
            }
         }
      }

      /// <summary>
      /// Sets the selected font;
      /// </summary>
      private void SetSelectedFont ()
      {
         if ((this.SelectedFont == null || this.SelectedFont.Source != this.m_FontName) &&
             !string.IsNullOrEmpty (this.m_FontName))
         {
            try
            {
               this.SelectedFont = new FontFamily (this.m_FontName);
            }
            catch (Exception ex)
            {
               this.SelectedFont = new FontFamily ("Arial");
               Console.Error.WriteLine (ex.Message);
            }
         }
      }

      /// <summary>
      /// Gets or Sets the font size.
      /// </summary>
      public double FontSize
      {
         get { return this.m_FontSize; }
         set
         {
            if (!this.m_FontSize.Equals (value))
            {
               this.m_FontSize = value;
               this.RaisePropertyChanged ("FontSize");
            }
         }
      }

      /// <summary>
      /// Gets the name of the option page.
      /// </summary>
      [XmlIgnore]
      public string Name
      {
         get { return "Editor"; }
      }

      /// <summary>
      /// Gets the icon of the option page.
      /// </summary>
      [XmlIgnore]
      public MainMenuIcon OptionPageIcon
      {
         get { return MainMenuIcon.Editalt; }
      }

      /// <summary>
      /// Gets the selected font.
      /// </summary>
      [XmlIgnore]
      public FontFamily SelectedFont
      {
         get { return this.m_SelectedFont; }
         set
         {
            if (!Equals (this.m_SelectedFont, value))
            {
               this.m_SelectedFont = value;
               this.RaisePropertyChanged ("SelectedFont");
               this.FontName = this.m_SelectedFont.Source;
            }
         }
      }

      /// <summary>
      /// Gets or Sets if the code folding flag.
      /// </summary>
      public bool CodeFolding
      {
          get { return this.m_CodeFolding; }
          set
          {
              this.m_CodeFolding = value;
              this.RaisePropertyChanged("CodeFolding");
          }
      }

      /// <summary>
      /// Loads the data from xml.
      /// </summary>
      /// <param name="xmlToLoad">Xml string to load.</param>
      public void LoadFromXml (string xmlToLoad)
      {
         OptionsEditor loadedData = null;
         try
         {
            loadedData = Serialization.DeserializeFromString <OptionsEditor> (xmlToLoad);
         }
         catch (Exception ex)
         {
            Console.Error.WriteLine (ex.Message);
         }

         if (loadedData != null)
            this.CopyPropertiesFrom (loadedData);
      }

      /// <summary>
      /// Saves any data to xml.
      /// </summary>
      /// <returns>The data to save in Xml format.</returns>
      public string SaveToXml ()
      {
         return this.Serialize ();
      }

      #endregion
   }
}
